#include "log_controller.h"

log_controller log_config;

log_controller::log_controller() {
	this->log_level = PACMEN_LOG_ERROR;
	this->log_output = PACMEN_LOG_STDOUT;
	this->output_file = NULL;
}

log_controller::log_controller(pacmen_log_level level, const char *filename) {
	this->log_level = level;
	this->log_output = PACMEN_LOG_FILE;

	if ((this->output_file = fopen(filename, "a")) == NULL) {
		this->log_output = PACMEN_LOG_STDOUT;
		this->output_file = stdout;
	}

}

log_controller::log_controller(pacmen_log_level level, pacmen_log_output output) {
	this->log_level = level;
	this->log_output = output;

	if (output == PACMEN_LOG_STDOUT)
		this->output_file = stdout;
	else
		this->output_file = stderr;
}

log_controller::~log_controller() {
	if (this->log_output == PACMEN_LOG_FILE)
		fclose(this->output_file);
}

void log_controller::print(pacmen_log_level log_level, const char *str, ...) {
	int i;
	time_t rawtime;
	time(&rawtime);

	char *time_string = ctime(&rawtime);
	time_string[strlen(time_string)-1] = '\0';

	if (log_level > this->log_level)
		return;

	switch (log_level) {
	case PACMEN_LOG_ERROR:
		fprintf(this->output_file, "[ERROR] ");
		break;
	case PACMEN_LOG_INFO:
		fprintf(this->output_file, "[INFO] ");
		break;
	case PACMEN_LOG_DEBUG:
		fprintf(this->output_file, "[DEBUG] ");
		break;
	}

	fprintf(this->output_file, "on %s: ", time_string);

	va_list arguments;
	va_start(arguments, str);

	for (i=0; str[i] != '\0'; i++) {
		if (str[i] != '%')
			fprintf(this->output_file, "%c", str[i]);
		else {
			switch(str[++i]) {
				case 'd':
					fprintf(this->output_file, "%d", va_arg(arguments, int));
					break;
				case 's':
					fprintf(this->output_file, "%s", va_arg(arguments, char *));
					break;
				case 'l':
					fprintf(this->output_file, "%lld", va_arg(arguments, long long int));
					break;
				case '%':
					fprintf(this->output_file, "%%");
					break;
				default:
					break;
			}
		}
	}

	if (this->log_output == PACMEN_LOG_FILE)
		fflush(this->output_file);
}

void log_controller::print(pacmen_log_level log_level, pacmen_log_fileattribute file_attribute, const char *str, ...) {
	int i;
	time_t rawtime;
	time(&rawtime);

	char *time_string = ctime(&rawtime);
	time_string[strlen(time_string)-1] = '\0';

	if (log_level > this->log_level)
		return;

	switch (log_level) {
	case PACMEN_LOG_ERROR:
		fprintf(this->output_file, "[ERROR] ");
		break;
	case PACMEN_LOG_INFO:
		fprintf(this->output_file, "[INFO] ");
		break;
	case PACMEN_LOG_DEBUG:
		fprintf(this->output_file, "[DEBUG] ");
		break;
	}

	fprintf(this->output_file, "on %s: ", time_string);
	fprintf(this->output_file, "by %s on %s:%d: ", file_attribute.function, file_attribute.file, file_attribute.line);

	va_list arguments;
	va_start(arguments, str);

	for (i=0; str[i] != '\0'; i++) {
		if (str[i] != '%')
			fprintf(this->output_file, "%c", str[i]);
		else {
			switch(str[++i]) {
				case 'd':
					fprintf(this->output_file, "%d", va_arg(arguments, int));
					break;
				case 's':
					fprintf(this->output_file, "%s", va_arg(arguments, char *));
					break;
				case 'l':
					fprintf(this->output_file, "%lld", va_arg(arguments, long long int));
					break;
				case '%':
					fprintf(this->output_file, "%%");
					break;
				default:
					break;
			}
		}
	}

	if (this->log_output == PACMEN_LOG_FILE)
		fflush(this->output_file);
}

log_controller & log_controller::operator <<(int value) {
	time_t rawtime;
	time(&rawtime);

	char *time_string = ctime(&rawtime);
	time_string[strlen(time_string)-1] = '\0';

	fprintf(this->output_file, "[DEBUG] on %s: %d", time_string, value);

	if (this->log_output == PACMEN_LOG_FILE)
		fflush(this->output_file);

	return *this;
}

log_controller & log_controller::operator >>(int value) {
	fprintf(this->output_file, "%d", value);

	return *this;
}

log_controller & log_controller::operator <<(const char *str) {
	time_t rawtime;
	time(&rawtime);

	char *time_string = ctime(&rawtime);
	time_string[strlen(time_string)-1] = '\0';

	fprintf(this->output_file, "[DEBUG] on %s: %s", time_string, str);

	if (this->log_output == PACMEN_LOG_FILE)
		fflush(this->output_file);

	return *this;
}

log_controller & log_controller::operator >>(const char *str) {
	fprintf(this->output_file, "%s", str);

	return *this;
}

log_controller & log_controller::operator <<(double value) {
	time_t rawtime;
	time(&rawtime);

	char *time_string = ctime(&rawtime);
	time_string[strlen(time_string)-1] = '\0';

	fprintf(this->output_file, "[DEBUG] on %s: %f", time_string, value);

	if (this->log_output == PACMEN_LOG_FILE)
		fflush(this->output_file);

	return *this;
}

log_controller & log_controller::operator >>(double value) {
	fprintf(this->output_file, "%f", value);

	return *this;
}

pacmen_log_fileattribute log_controller::file_attribute(const char *file, const char *function, int line) {
	pacmen_log_fileattribute file_attribute;

	file_attribute.file = file;
	file_attribute.function = function;
	file_attribute.line = line;

	return file_attribute;
}
